# -*- coding: utf-8 -*-
"""
__author__ = 'bingo'
__date__ = '2019/3/6'
# code is far away from bugs with the god animal protecting
    I love animals. They taste delicious.
              ┏┓      ┏┓
            ┏┛┻━━━┛┻┓
            ┃      ☃      ┃
            ┃  ┳┛  ┗┳  ┃
            ┃      ┻      ┃
            ┗━┓      ┏━┛
                ┃      ┗━━━┓
                ┃  神兽保佑    ┣┓
                ┃　永无BUG！   ┏┛
                ┗┓┓┏━┳┓┏┛
                  ┃┫┫  ┃┫┫
                  ┗┻┛  ┗┻┛
"""
import re
from django import forms
from django.core.validators import RegexValidator
from django_redis import get_redis_connection
from dj_youkou import constant
from user.models import User
from utils.FormMixin import FormMixin
from django.db.models import Q


class RegisterForm(forms.Form, FormMixin):
    """
    用于用户注册时调教的数据校验

    """
    telValidator = RegexValidator(r'^1[3-9]\d{9}$', message='手机号有误')

    username = forms.CharField(label='用户名', max_length=20, min_length=4, required=True,
                               error_messages=
                               {
                                   'max_length': '用户名长度不不能大于20',
                                   'min_length': '用户名长度不不能小于4',
                                   'required': '用户名不能为空',
                               })

    password = forms.CharField(label='密码', max_length=20, min_length=6, required=True,
                               error_messages=
                               {
                                   'max_length': '密码长度不不能大于20',
                                   'min_length': '密码长度不不能小于4',
                                   'required': '密码不能为空',
                               })

    password_repeat = forms.CharField(label='确认密码', max_length=20, min_length=6, required=True,
                                      error_messages=
                                      {
                                          'max_length': '密码长度不不能大于20',
                                          'min_length': '密码长度不不能小于4',
                                          'required': '密码确认不能为空',
                                      })

    tel = forms.CharField(label='手机号', max_length=11, min_length=11, validators=[telValidator, ], required=True,
                          error_messages=
                          {
                              'max_length': '手机号长度有误',
                              'min_length': '手机号长度有误',
                              'required': '手机号不能为空'
                          })

    sms_code = forms.CharField(max_length=constant.SMS_VERIFICATION_CODE_NUM,
                               min_length=constant.SMS_VERIFICATION_CODE_NUM, required=True,
                               error_messages=
                               {
                                   'max_length': '验证码不正确',
                                   'min_length': '验证码不正确',
                                   'required': '验证码不能为空'
                               })

    def clean_username(self):
        """
        校验用户名是否已存在
        :return:
        """
        username = self.cleaned_data.get('username')
        if User.objects.filter(username=username).exists():
            raise forms.ValidationError("用户名已存在")
        return username

    def clean_tel(self):
        """
        校验手机号是否已被注册
        :return:
        """
        tel = self.cleaned_data.get('tel')
        if User.objects.filter(mobile=tel).exists():
            raise forms.ValidationError("手机号已被注册")
        return tel

    def clean(self):
        """
        密码校验，手机验证码校验，手机号校验等等
        :return:
        """
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        password_repeat = cleaned_data.get('password_repeat')
        tel = cleaned_data.get('tel')
        sms_code = cleaned_data.get('sms_code')
        # 获取数据

        sms_code_key = 'sms_key_{}'.format(tel)
        conn_redis = get_redis_connection('sms_code')
        real_sms_code = conn_redis.get(sms_code_key)

        if (not real_sms_code) or (sms_code != real_sms_code.decode('utf-8')):
            """
            从redis中获取手机验证码，判断验证码是否正确
            """
            raise forms.ValidationError("手机验证码不正确")

        if password and password_repeat and (password != password_repeat):
            """
            验证两次密码是否一致
            """
            raise forms.ValidationError("两次密码不一致")


class LoginForm(forms.Form, FormMixin):
    """
    用于用户登录时的数据校验,account可以是用户名，也可以是手机号
    """

    account = forms.CharField(label='用户名或手机号',
                              error_messages=
                              {
                                  'required': '用户名或手机号不能为空'
                              })

    password = forms.CharField(label='密码', min_length=6, max_length=20, required=True,
                               error_messages=
                               {
                                   "min_length": "密码不正确，最小长度为6",
                                   "max_length": "密码不正确，最大长度为20",
                                   "required": "密码为空"
                               })
    remember = forms.BooleanField(required=False)

    def clean_account(self):
        account = self.cleaned_data.get('account')
        if (not re.match(r'^1[3-9]\d{9}$', account)) and (not re.match(r'^\w{5,20}$', account)):
            """
            当账号输入的不为手机号时，且用户名不在5-20个字符长度时
            """
            raise forms.ValidationError("用户账号信息不正确，请重新输入")
        return account

    def clean(self):
        cleaned_data = super(LoginForm, self).clean()
        account = cleaned_data.get('account')
        # account可能为手机号也可能为用户名
        password = cleaned_data.get('password')
        user_query = User.objects.filter(Q(username=account) | Q(mobile=account))
        if not user_query:
            """
            如果未查询到用户,抛出异常
            """
            raise forms.ValidationError("用户账号信息不存在")
        else:
            user = user_query.first()
            if not user.check_password(password):
                """
                如果查询到用户，但是密码不正确，抛出异常
                """
                raise forms.ValidationError("密码不正确")

    @property
    def user(self):
        """
        :return:返回一个 (username=account or mobile=account）的User()对象
        """
        account = self.cleaned_data.get('account')
        user = User.objects.filter(Q(username=account) | Q(mobile=account)).first()
        return user


class RetrievePasswordForm(forms.Form, FormMixin):
    """
    用于用户忘记密码时重置密码提交参数的校验

    """
    telValidator = RegexValidator(r'^1[3-9]\d{9}$', message='无效的手机号码，请检查')
    tel = forms.CharField(label='手机号', max_length=11, min_length=11, validators=[telValidator, ], required=True,
                          error_messages=
                          {
                              'max_length': '无效的手机号码，请检查',
                              'min_length': '无效的手机号码，请检查',
                              'required': '无效的手机号码，请检查'
                          })

    sms_code = forms.CharField(max_length=constant.SMS_VERIFICATION_CODE_NUM, required=True,
                               min_length=constant.SMS_VERIFICATION_CODE_NUM,
                               help_text="短信验证码", error_messages=
                               {
                                   'max_length': '短信验证码不正确',
                                   'min_length': '短信验证码不正确',
                                   'required': '请输入有效的短信验证码',
                               })
    password = forms.CharField(label='密码', max_length=20, min_length=6, required=True,
                               error_messages=
                               {
                                   'max_length': '密码长度不不能大于20',
                                   'min_length': '密码长度不不能小于4',
                                   'required': '密码不能为空',
                               })

    password_confirm = forms.CharField(label='确认密码', max_length=20, min_length=6, required=True,
                                       error_messages=
                                       {
                                           'max_length': '密码长度不不能大于20',
                                           'min_length': '密码长度不不能小于4',
                                           'required': '密码确认不能为空',
                                       })

    def clean(self):
        cleaned_data = super(RetrievePasswordForm, self).clean()
        redis_conn = get_redis_connection(alias='sms_code')
        tel = cleaned_data.get('tel')
        sms_code = cleaned_data.get('sms_code')
        password = cleaned_data.get('password')
        password_confirm = cleaned_data.get('password_confirm')

        sms_ret_key = 'sms_ret_{}'.format(tel)
        # 修改密码时存入redis的手机验证码
        sms_ret_value = redis_conn.get(sms_ret_key)
        if not User.objects.filter(mobile=tel).exists():
            raise forms.ValidationError("该手机号尚未被注册")

        if not sms_ret_value or (sms_ret_value.decode('utf-8') != sms_code):
            """
            根据手机号查询手机验证码，判断手机验证码是否为空或者用户传来的验证码和redis中的是否一致
            """
            raise forms.ValidationError("重置密码失败，手机验证码不正确")
        if password and password_confirm and (password != password_confirm):
            """
            判断两次密码是否一致
            """
            raise forms.ValidationError("重置密码失败，两次密码不一致")

    @property
    def user(self):
        user=User.objects.filter(mobile=self.cleaned_data.get('tel'))
        return user